(function(){
    "use strict";
    //1.实用方法
    //2.动画
    //3.ajax
    //4.dom
    //5.表单序列化
    //6.事件
    //7.offset
    //8.模板引擎
    //9.剪切板
    //10.JSON解析

    window.$ = {
        author: "Maxwell",
        version: "1.0.0",

        //1.实用方法
        each : function (array, fn) {
            for (var i = 0; i < array.length; i++) {
                fn(array[i], i);
            }
        },
        map : function (obj, fn) {
            for (var k in obj) {
                fn(k, obj[k]);
            }
        },
        isJSON : function(str) {
            if (typeof str == 'string') {
                try {
                    JSON.parse(str);
                    return true;
                } catch(e) {
                    return false;
                }
            }
            return false;
        },
        getQueryString : function(name) {
            var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
            var r = location.search.substr(1).match(reg);
            if(r!=null)return  decodeURI(r[2]); return null;
        },
        loadScript : function(files) {
            this.each(files, function(file) {
                var scriptTag = document.createElement('script');
                scriptTag.async = false;
                scriptTag.src = file;
                document.body.appendChild(scriptTag);
            });
        },
        now : function () {
            var date = new Date();
            return date.getTime();
        },
        random : function (start, end) {
            return start + parseInt(Math.random() * (end - start));
        },
        shuffle : function (arr) {
            var result = [],
              rand;
            while (arr.length > 0) {
                rand = this.random(0, arr.length);
                result.push(arr[rand]);
                arr.splice(rand, 1);
            }
            return result;
        },
        sample : function (arr, num) {
            var result = [];
            for (var i = 0; i < num; i++) {
                while (true) {//循环去找到一个合适的随机数，找到后退出循环
                    var index = this.random(0, arr.length);
                    //如果在数组当中找不到当前的这个数，则index可用
                    if (result.indexOf(arr[index]) == -1) {
                        break;
                    }
                }
                result.push(arr[index]);
            }
            return result;
        },
        //2.动画
        Tween :{
            Linear: function(t, b, c, d) {
                return c * t / d + b;
            },
            //二次的
            QuadEaseIn: function(t, b, c, d) {
                return c * (t /= d) * t + b;
            },
            QuadEaseOut: function(t, b, c, d) {
                return -c * (t /= d) * (t - 2) + b;
            },
            QuadEaseInOut: function(t, b, c, d) {
                if ((t /= d / 2) < 1) return c / 2 * t * t + b;
                return -c / 2 * ((--t) * (t - 2) - 1) + b;
            },
            //三次的
            CubicEaseIn: function(t, b, c, d) {
                return c * (t /= d) * t * t + b;
            },
            CubicEaseOut: function(t, b, c, d) {
                return c * ((t = t / d - 1) * t * t + 1) + b;
            },
            CubicEaseInOut: function(t, b, c, d) {
                if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
                return c / 2 * ((t -= 2) * t * t + 2) + b;
            },
            //四次的
            QuartEaseIn: function(t, b, c, d) {
                return c * (t /= d) * t * t * t + b;
            },
            QuartEaseOut: function(t, b, c, d) {
                return -c * ((t = t / d - 1) * t * t * t - 1) + b;
            },
            QuartEaseInOut: function(t, b, c, d) {
                if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
                return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
            },
            QuintEaseIn: function(t, b, c, d) {
                return c * (t /= d) * t * t * t * t + b;
            },
            QuintEaseOut: function(t, b, c, d) {
                return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
            },
            QuintEaseInOut: function(t, b, c, d) {
                if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
                return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
            },
            //正弦的
            SineEaseIn: function(t, b, c, d) {
                return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
            },
            SineEaseOut: function(t, b, c, d) {
                return c * Math.sin(t / d * (Math.PI / 2)) + b;
            },
            SineEaseInOut: function(t, b, c, d) {
                return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
            },
            ExpoEaseIn: function(t, b, c, d) {
                return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
            },
            ExpoEaseOut: function(t, b, c, d) {
                return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
            },
            ExpoEaseInOut: function(t, b, c, d) {
                if (t == 0) return b;
                if (t == d) return b + c;
                if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
                return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
            },
            CircEaseIn: function(t, b, c, d) {
                return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
            },
            CircEaseOut: function(t, b, c, d) {
                return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
            },
            CircEaseInOut: function(t, b, c, d) {
                if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
                return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
            },
            ElasticEaseIn: function(t, b, c, d, a, p) {
                if (t == 0) return b;
                if ((t /= d) == 1) return b + c;
                if (!p) p = d * .3;
                if (!a || a < Math.abs(c)) {
                    a = c;
                    var s = p / 4;
                } else var s = p / (2 * Math.PI) * Math.asin(c / a);
                return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
            },
            ElasticEaseOut: function(t, b, c, d, a, p) {
                if (t == 0) return b;
                if ((t /= d) == 1) return b + c;
                if (!p) p = d * .3;
                if (!a || a < Math.abs(c)) {
                    a = c;
                    var s = p / 4;
                } else var s = p / (2 * Math.PI) * Math.asin(c / a);
                return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
            },
            ElasticEaseInOut: function(t, b, c, d, a, p) {
                if (t == 0) return b;
                if ((t /= d / 2) == 2) return b + c;
                if (!p) p = d * (.3 * 1.5);
                if (!a || a < Math.abs(c)) {
                    a = c;
                    var s = p / 4;
                } else var s = p / (2 * Math.PI) * Math.asin(c / a);
                if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
                return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
            },
            //冲过头系列
            BackEaseIn: function(t, b, c, d, s) {
                if (s == undefined) s = 1.70158;
                return c * (t /= d) * t * ((s + 1) * t - s) + b;
            },
            BackEaseOut: function(t, b, c, d, s ) {
                if (s == undefined) s = 1.70158;
                return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
            },
            BackEaseInOut: function(t, b, c, d, s) {
                if (s == undefined) s = 1.70158;
                if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
                return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
            },
            //弹跳系列
            BounceEaseIn: function(t, b, c, d) {
                return c - this.Tween.BounceEaseOut(d - t, 0, c, d) + b;
            },
            BounceEaseOut: function(t, b, c, d) {
                if ((t /= d) < (1 / 2.75)) {
                    return c * (7.5625 * t * t) + b;
                } else if (t < (2 / 2.75)) {
                    return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
                } else if (t < (2.5 / 2.75)) {
                    return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
                } else {
                    return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
                }
            },
            BounceEaseInOut: function(t, b, c, d) {
                if (t < d / 2) return this.Tween.BounceEaseIn(t * 2, 0, c, d) * .5 + b;
                else return this.Tween.BounceEaseOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
            }
        },
        animate : function (elem, targetJSON, time, tweenString, callback) {
            if (arguments.length < 3 || typeof arguments[0] != "object" || typeof arguments[1] != "object" || typeof arguments[2] != "number") {
                throw new Error("对不起，你传进来的参数数量不对或者参数类型不对，请仔细检查哦！");
                return;
            } else if (arguments.length == 3) {
                tweenString = "Linear";
                callback = null;
            } else if (arguments.length == 4) {
                switch (typeof arguments[3]) {
                    case "string" :
                        callback = null;
                        break;
                    case "function" :
                        callback = arguments[3];
                        tweenString = "Linear";
                        break;
                    default :
                        throw new Error("抱歉，第4个参数要么是缓冲描述词，要么是回调函数，请检查！");
                }
            }
            if (window.navigator.userAgent.indexOf("MSIE") != -1) {
                var interval = 50;
            } else {
                var interval = 20;
            }
            elem.isanimated = true;
            var originalJSON = {};
            var deltaJSON = {};
            for (var k in targetJSON) {
                originalJSON[k] = parseFloat(this.fetchComputedStyle(elem, k));
                targetJSON[k] = parseFloat(targetJSON[k]);
                deltaJSON[k] = targetJSON[k] - originalJSON[k];
            }
            var maxFrameNumber = time / interval;
            var frameNumber = 0;
            var n;

            var self=this;
            var timer = setInterval(function () {
                for (var k in originalJSON) {
                    n = self.Tween[tweenString](frameNumber, originalJSON[k], deltaJSON[k], maxFrameNumber);
                    if (k != "opacity") {
                        elem.style[k] = n + "px";
                    } else {
                        elem.style[k] = n;
                        elem.style.filter = "alpha(opacity=" + n * 100 + ")";
                    }
                }

                frameNumber++;
                if (frameNumber == maxFrameNumber) {
                    for (var k in targetJSON) {
                        if (k != "opacity") {
                            elem.style[k] = targetJSON[k] + "px";
                        } else {
                            elem.style[k] = targetJSON[k];
                            elem.style.filter = "alpha(opacity=" + (targetJSON[k] * 100) + ")";
                        }
                    }
                    clearInterval(timer);
                    elem.isanimated = false;
                    callback && callback.apply(elem);
                }
            }, interval);
        },
        fetchComputedStyle : function (obj, property) {
            if (window.getComputedStyle) {
                property = property.replace(/([A-Z])/g, function (match, $1) {
                    return "-" + $1.toLowerCase();
                });
                return window.getComputedStyle(obj)[property];
            } else {
                property = property.replace(/-([a-z])/g, function (match, $1) {
                    return $1.toUpperCase();
                });
                return obj.currentStyle[property];
            }
        },
        //3.Ajax
        preLoadImg : function(url, callback) {
          var img = new Image();
          img.src = url;
          //兼容ie、opera刷新页面时，不触发onload事件
          if (img.complete) { // 如果图片已经存在于浏览器缓存，直接调用回调函数
              callback(img);
              return; // 直接返回，不用再处理onload事件
          }
          img.onload = function() { //图片下载完毕时异步调用callback函数。
              callback(img);
          };
        },
        loadTemplate : function(URL, callback) {
          var xhr = this.createXMLHttpRequest();
            xhr.onreadystatechange = function(){
                if (xhr.readyState == 4) {
                    if (xhr.status >= 200 && xhr.status < 300 || xhr.status==304) {
                        callback(null, xhr.responseText);
                    } else {
                        callback(new Error('没有找到请求的文件', undefined));
                    }
                }
            };
            xhr.open("GET", URL, false);
            xhr.send(null);
        },
        get : function (URL, queryJSON, callback, header) {
            var xhr = this.createXMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if (xhr.status >= 200 && xhr.status < 300
                        || xhr.status == 304) {
                        callback(null, xhr.responseText);
                    } else {
                        callback(new Error("没有找到请求的文件"),
                            undefined);
                    }
                }
            };
            var queryString = queryJSON;
            if (typeof queryJSON == "object") {
                queryString =this._queryjson2querystring(queryJSON);
            }
            xhr.open("GET", URL + "?" + queryString, true);
            if (!!header && typeof header == 'object') {
                for(var h in header) {
                    xhr.setRequestHeader(h, header[h]);
                }
            }
            xhr.send(null);
        },

        post : function (URL, queryJSON, callback, header) {
            var xhr = this.createXMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if (xhr.status >= 200 && xhr.status < 300
                      || xhr.status == 304) {
                        callback(null, xhr.responseText);
                    } else {
                        callback(new Error("没有找到请求的文件"), undefined);
                    }
                }
            };
            xhr.open("POST", URL, true);
            var queryString = queryJSON;
            if (typeof queryJSON == "object") {
                queryString =
                  this._queryjson2querystring(queryJSON);
            }
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            //如果需要传递自定义header
            // xhr.setRequestHeader('token','7396777491f1a0f4af4deffd741cb3ee');
            if (!!header && typeof header == 'object') {
                for(var h in header) {
                    xhr.setRequestHeader(h, header[h]);
                }
            }
            xhr.send(queryString);
        },
        jsonp : function (URL, queryJSON, callbackname, callback) {
            window[callbackname] = callback;
            var scriptObj = document.createElement("script");
            document.body.appendChild(scriptObj);
            var querystring = this._queryjson2querystring(queryJSON);
            scriptObj.src = querystring ? (URL + "?" + querystring) : URL;
            document.body.removeChild(scriptObj);
        },
        _queryjson2querystring : function (json) {
            var arr = [];
            for (var k in json) {
                arr.push(k + "=" + encodeURIComponent(json[k]));
            }
            return arr.join("&");
        },
        ajax : function(){
            var ajaxData = {
                type:arguments[0].type || "GET",
                url:arguments[0].url || "",
                async:arguments[0].async || "true",
                data:arguments[0].data || null,
                dataType:arguments[0].dataType || "text",
                contentType:arguments[0].contentType || "application/x-www-form-urlencoded",
                beforeSend:arguments[0].beforeSend || function(){},
                success:arguments[0].success || function(){},
                error:arguments[0].error || function(){}
            };
            ajaxData.beforeSend();
            var xhr = this.createXMLHttpRequest();
            xhr.responseType=ajaxData.dataType;
            var querystring = this._queryjson2querystring(ajaxData.data);
            xhr.open(ajaxData.type,ajaxData.url+"?"+querystring,ajaxData.async);
            xhr.setRequestHeader("Content-Type",ajaxData.contentType);
            xhr.send(this.convertData(ajaxData.data));
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4) {
                    if(xhr.status == 200){
                        ajaxData.success(xhr.response)
                    }else{
                        ajaxData.error()
                    }
                }
            }
        },
        createXMLHttpRequest : function() {
            if (window.ActiveXObject) {
                return new ActiveXObject("Microsoft.XMLHTTP");
            } else if (window.XMLHttpRequest) {
                return new XMLHttpRequest();
            }
        },
        convertData : function(data){
            if( typeof data === 'object' ){
                var convertResult = "" ;
                for(var c in data){
                    convertResult+= c + "=" + data[c] + "&";
                }
                convertResult=convertResult.substring(0,convertResult.length-1)
                return convertResult;
            }else{
                return data;
            }
        },
        //4.DOM
        children : function (obj, num) {
            var arr = [];
            for (var i = 0; i < obj.childNodes.length; i++) {
                var o = obj.childNodes[i];
                if (o.nodeType == Node.ELEMENT_NODE) {
                    arr.push(o);
                }
            }
            return  (num || num === 0)?arr[num] : arr;
        },
        prevSibling : function (obj) {
            var prev = obj;
            while (prev = prev.previousSibling) {
                if (prev.nodeType == Node.ELEMENT_NODE) {
                    return prev;
                }
            }
            return null;
        },
        prevAll : function (obj) {
            var arr = [];
            while (obj = obj.previousSibling) {
                if (obj.nodeType == 1) {
                    arr.push(obj);
                }
            }
            return arr;
        },
        getElementsByClassName : function (className) {
            if (document.getElementsByClassName) {
                return document.getElementsByClassName(className);
            } else {
                var aEle = document.getElementsByTagName("*");
                var arr = [];
                for (var i = 0; i < aEle.length; i++) {
                    var obj = aEle[i];
                    if (obj.className == className) {
                        arr.push(obj);
                    }
                }
                return arr;
            }
        },
        hasClass : function(ele, cls) {
            if (!ele || !cls) return false;
            if (ele.classList) {
                return ele.classList.contains(cls);
            } else {
                return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
            }
        },
        addClass : function(ele, cls) {
            if (ele.classList) {
                ele.classList.add(cls);
            } else {
                if (!this.hasClass(ele, cls)) ele.className += '' + cls;
            }
        },
        removeClass : function(ele, cls) {
            if (ele.classList) {
                ele.classList.remove(cls);
            } else {
                ele.className = ele.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
            }
        },
        //5.表单序列化
        serializeArray : function (form) {
            var elems = form.elements;
            var arr = [];
            for (var i = 0; i < elems.length; i++) {
                var e = elems[i];
                switch (e.type) {
                    case "button" :
                    case "submit" :
                    case "reset" :
                        break;
                    case "text" :
                    case "password" :
                    case "textarea" :
                    case "hidden" :
                        arr.push(e.name + "=" + e.value);
                        break;
                    case "radio":
                    case "checkbox":
                        e.checked && arr.push(e.name + "=" + e.value);
                        break;
                    case "select-one":
                        var options = e.getElementsByTagName("option");
                        console.log(options);
                        for (var j = 0; j < options.length; j++) {
                            if (options[j].selected) {
                                arr.push(e.name + "=" + options[j].value);
                            }
                        }
                        break;
                }
            }
            return arr;
        },
        serializeString : function (form) {
            return this.serializeArray(form).join("&");
        },
        //6.事件
        addEvent : function (obj, eventType, fn) {
            if (obj.addEventListener) {
                obj.addEventListener(eventType, fn, false);
            } else if (obj.attachEvent) {
                obj.attachEvent("on" + eventType, function () {
                    fn.call(obj);
                });
            } else {
                obj["on" + eventType] = fn;
            }
        },
        removeEvent : function(element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }
        },
        getEvent: function(event){
            return event ? event : window.event;
        },
        getTarget: function(event){
            return event.target || event.srcElement;
        },
        preventDefault: function(event){
            if (event.preventDefault){
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },
        stopPropagation: function(event){
            if (event.stopPropagation){
                event.stopPropagation();
            } else {
                event.cancelBubble = true;
            }
        },
        //7.offset
        getAllTop : function (obj) {
            var allTop = obj.offsetTop;
            var currentObj = obj;
            while (currentObj = currentObj.offsetParent) {
                allTop += currentObj.offsetTop;
            }
            return allTop;
        },
        getAllLeft : function (obj) {
            var allLeft = obj.offsetLeft;
            var currentObj = obj;
            while (currentObj = currentObj.offsetParent) {
                allLeft += currentObj.offsetLeft;
            }
            return allLeft;
        },
        //8.模板
        compile : function (templateString, dictionary) {
            return templateString.replace(/\%([0-9A-Za-z_]+)\%/g, function (match, $1) {
                return dictionary[$1];
            });
        },
        //9.剪切板
        getClipboardText : function(event){
            var clipboardData = (event.clipboardData || window.clipboardData);
            return clipboardData.getData("text");
        },
        setClipboardText : function(event, value){
            if (event.clipboardData){
                return event.clipboardData.setData("text/plain", value);
            } else if (window.clipboardData){
                return window.clipboardData.setData("text", value);
            }
        }
    }
})();

